#include "TableWidgetShell.h"
#include "../../Utility/XXlogger.h"

TableWidgetShell::TableWidgetShell(QObject *parent)
    : QObject (parent){
    _tableWidget = nullptr;
    _currentSelectGroup = nullptr;
    _currentActiveGroup = nullptr;
}
void TableWidgetShell::shell(QTableWidget *tableWidget){
    if(_tableWidget){
        xxErr("could not reset tableWidget that is not nullptr.");
        return;
    }
    _tableWidget = tableWidget;
    connect(_tableWidget,&QTableWidget::cellClicked,this,&TableWidgetShell::tableWidget_onCellClicked);
}

void TableWidgetShell::configColumn(const QStringList titles, const QStringList &names, const QList<QMetaObject> &cls){
    if(titles.count() != names.count() || names.count() != cls.count()){
        return;
    }
    _tableWidget->setColumnCount(titles.count());
    _tableWidget->setHorizontalHeaderLabels(titles);
    for (int index=0; index<names.count(); index++) {
        ColumnInfo info;
        info._title = titles[index];
        info._name = names[index];
        info._cellMeta = cls[index];
        _columnInfoList << info;
    }
}
TableWidgetShell& TableWidgetShell::appendColumn(QString title, QString name, QMetaObject cls){
    ColumnInfo info;
    info._title = title;
    info._name = name;
    info._cellMeta = cls;
    _columnInfoList << info;
    return *this;
}
TableWidgetShell& TableWidgetShell::appendColumn(QString title, QString name, std::function<CellBase*(void)> block){
    ColumnInfo info;
    info._title = title;
    info._name = name;
    info._cellBlock = block;
    _columnInfoList << info;
    return *this;
}
void TableWidgetShell::endConfigColumn(){
    QStringList titles;
    for (auto iter=_columnInfoList.begin(); iter!=_columnInfoList.end(); ++iter) {
        titles.append(iter->_title);
    }
    _tableWidget->setColumnCount(titles.count());
    _tableWidget->setHorizontalHeaderLabels(titles);
}
void TableWidgetShell::configSelectable(bool selectable){
    if(selectable){
        connect(_tableWidget,&QTableWidget::cellDoubleClicked,this,&TableWidgetShell::tableWidget_onCellDoubleClicked);
    }
    else {
        disconnect(_tableWidget,&QTableWidget::cellDoubleClicked,this,&TableWidgetShell::tableWidget_onCellDoubleClicked);
    }
}

void TableWidgetShell::appendData(const QVariantMap &data){
    int row = _tableWidget->rowCount();
    _tableWidget->setRowCount(row+1);

    TableRowCellGroup *group = new TableRowCellGroup(_tableWidget,row,_columnInfoList,data);
    connect(group,&TableRowCellGroup::sigEvent,this,&TableWidgetShell::tableRowCellGroup_onEvent);
    connect(group,&TableRowCellGroup::sigDataChanged,this,&TableWidgetShell::tableRowCellGroup_onDataChanged);
    _groups << group;
}
void TableWidgetShell::insertData(int row, const QVariantMap &data){
    _tableWidget->insertRow(row);

    TableRowCellGroup *group = new TableRowCellGroup(_tableWidget,row,_columnInfoList,data);
    connect(group,&TableRowCellGroup::sigEvent,this,&TableWidgetShell::tableRowCellGroup_onEvent);
    connect(group,&TableRowCellGroup::sigDataChanged,this,&TableWidgetShell::tableRowCellGroup_onDataChanged);
    _groups << group;
}
void TableWidgetShell::removeData(int row){
    TableRowCellGroup *group = _groups.value(row,nullptr);
    if(nullptr == group){
        return;
    }
    group->delData();
    delete group;
    _tableWidget->removeRow(row);
}
QVariantList TableWidgetShell::getData(){
    QVariantList maps;
    for (int index=0; index<_groups.count(); index++) {
        maps<<_groups[index]->getData();
    }
    return maps;
}
QVariantMap TableWidgetShell::getData(int row){
    TableRowCellGroup *group = _groups.value(row,nullptr);
    if(nullptr == group){
        return QVariantMap();
    }
    return group->getData();
}
QVariantMap TableWidgetShell::takeData(int row){
    TableRowCellGroup *group = _groups.value(row,nullptr);
    if(nullptr == group){
        return QVariantMap();
    }
    QVariantMap data = group->getData();
    group->delData();
    delete group;
    _tableWidget->removeRow(row);
    return data;
}

void TableWidgetShell::setData(const QVariantList &datas){
    QStringList names;
    for (int row=0; row<datas.count(); row++) {
        if(row<_groups.count()){
            TableRowCellGroup *group = _groups[row];
            group->setData(datas[row].toMap());
        }
        else{
            appendData(datas[row].toMap());
        }

        QVariantMap map = _groups[row]->getData();
    }

    while(_groups.count()>datas.count()){
        delete _groups.takeLast();
        _tableWidget->removeRow(_tableWidget->rowCount()-1);
    }
}
void TableWidgetShell::setData(int row, const QVariantMap &data){
    TableRowCellGroup *group = _groups.value(row,nullptr);
    if(nullptr == group){
        return;
    }
    group->setData(data);
}
void TableWidgetShell::updateData(int row, const QVariantMap &data){
    TableRowCellGroup *group = _groups.value(row,nullptr);
    if(nullptr == group){
        return;
    }
    group->updateData(data);
}
void TableWidgetShell::select(int row){
    setCurrentSelectGroup(_groups.value(row,nullptr));
}
int TableWidgetShell::findRowEqualTo(const QVariantMap &data){
    for (int row=0; row<_groups.count(); row++) {
        QVariantMap map = _groups[row]->getData();
        bool matching = true;
        for (auto iter=data.begin(); iter!=data.end(); iter++) {
            if(!map.contains(iter.key()) || map.value(iter.key()) != iter.value()){
                matching = false;
                break;
            }
        }
        if(matching){
           return row;
        }
    }
    return -1;
}

void TableWidgetShell::setCurrentAcitveGroup(TableRowCellGroup *group){
    if(group == _currentActiveGroup){
        return;
    }
    if(_currentActiveGroup){
        _currentActiveGroup->setActived(false);
        disconnect(_currentActiveGroup,&QObject::destroyed,this,&TableWidgetShell::group_onDestroyed);
    }
    if(group){
        group->setActived(true);
        connect(group,&QObject::destroyed,this,&TableWidgetShell::group_onDestroyed);
    }
    _currentActiveGroup = group;
}
void TableWidgetShell::setCurrentSelectGroup(TableRowCellGroup *group){
    if(group == _currentSelectGroup){
        return;
    }
    if(_currentSelectGroup){
        _currentSelectGroup->setSelected(false);
        disconnect(_currentSelectGroup,&QObject::destroyed,this,&TableWidgetShell::group_onDestroyed);
    }
    if(group){
        group->setSelected(true);
        connect(group,&QObject::destroyed,this,&TableWidgetShell::group_onDestroyed);
    }
    int previous = _currentSelectGroup?_groups.indexOf(_currentSelectGroup):-1;
    int current = group?_groups.indexOf(group):-1;
    _currentSelectGroup = group;
    emit sigSelectionChanged(current,previous);
}

void TableWidgetShell::tableWidget_onCellClicked(int row, int column){
    Q_UNUSED(column);
    TableRowCellGroup *group = _groups.value(row,nullptr);
    setCurrentAcitveGroup(group);
}
void TableWidgetShell::tableWidget_onCellDoubleClicked(int row, int column){
    Q_UNUSED(column);
    TableRowCellGroup *previous = _currentSelectGroup;
    TableRowCellGroup *current = _groups.value(row,nullptr);
    if(current != previous){
        if(previous){
            previous->setSelected(false);
        }
        if(current){
            current->setSelected(true);
        }
        _currentSelectGroup = current;

        int previousRow = previous?_groups.indexOf(previous):-1;
        int currentRow = row;
        emit sigSelectionChanged(currentRow,previousRow);
    }
}
void TableWidgetShell::tableRowCellGroup_onEvent(QString name, QVariant info){
    TableRowCellGroup *group = qobject_cast<TableRowCellGroup*>(sender());
    int row = _groups.indexOf(group);
    emit sigEvent(row,name,info);
}
void TableWidgetShell::tableRowCellGroup_onDataChanged(){
    TableRowCellGroup *group = qobject_cast<TableRowCellGroup*>(sender());
    int row = _groups.indexOf(group);
    emit sigDataChanged(row);
}
void TableWidgetShell::group_onDestroyed(QObject *object){
    if(object == _currentActiveGroup){
        setCurrentAcitveGroup(nullptr);
    }
    if(object == _currentSelectGroup){
        setCurrentSelectGroup(nullptr);
    }
}
